/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package fr.umlv.qroxy.diagnostic;

import fr.umlv.qroxy.http.HttpException;
import fr.umlv.qroxy.http.HttpMethods;
import fr.umlv.qroxy.rules.HeaderHttp;
import fr.umlv.qroxy.rules.Rule;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Create an interface to check the Qroxy configuration
 *
 * @author Sebastien BAUDRAND <sebbaudrand@gmail.com>
 */
public class WebServer implements Runnable {

    private static final Logger logger = Logger.getLogger(WebServer.class.getName());
    private final int port;
    private final String confDirectory;
    private final ServerSocketChannel serverSocket;
    private final File directory;
    private ArrayList<Rule> rules = new ArrayList<Rule>();
    private final String p1 = "<!DOCTYPE html><HTML><HEAD><TITLE>Qroxy Interface</TITLE></HEAD><BODY><h1>Selection</h1><form action=\"Clear";
    private final String p2 = "\" method=\"POST\"><input type=\"submit\" name=\"Delete cache\" value=\"Delete cache\"></form><form action=\"Refresh";
    private final String p3 = "\" method=\"POST\"><input type=\"submit\" name=\"Refresh\" value=\"Refresh\"></form><h1>Cache Size</h1>";
    private final String p4 = "<h1>Rules</h1><TABLE COLSPAN=\"5\" CELLPADDING=10>";
    private final String p5 = "</TABLE></BODY></HTML>";

    public WebServer(int port, String conf, File dir, ArrayList<Rule> rules) throws IOException {
        this.port = port;
        this.confDirectory = conf;
        this.serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(port));
        this.directory = dir;
        this.rules.addAll(rules);
    }

    /**
     * Create the html code to the web interface
     *
     * @return a StringBuilder with the html code
     */
    private StringBuilder pageHtml() {
        StringBuilder sb = new StringBuilder();
        sb.append("HTTP/1.0 200 OK");
        sb.append("\n\r");
        sb.append("Date: ");
        sb.append(new Date());
        sb.append("\n\r");
        sb.append("\n\r");
        sb.append(p1);
        sb.append(p2);
        sb.append(p3);
        sb.append(String.valueOf(countCacheSize()));
        sb.append(" MB");
        sb.append(p4);
        sb.append(showRulesInformations());
        sb.append(p5);

        return sb;
    }

    private StringBuilder pageHtmlS() {

        StringBuilder sb = new StringBuilder();
        sb.append("HTTP/1.0 200 OK");
        sb.append("\n\r");
        sb.append("Date: ");
        sb.append(new Date());
        sb.append("\n\r");
        sb.append("\n\r");
        sb.append(p1);
        sb.append(p2);
        sb.append(p3);
        sb.append("<h3><font color=\"GREEN\"> Cache deleted </font></h3>");
        sb.append(String.valueOf(countCacheSize()));
        sb.append(" MB");
        sb.append(p4);
        sb.append(showRulesInformations());
        sb.append(p5);

        return sb;
    }

    /**
     * Get the lenght of the cache directory
     *
     * @return double
     */
    public String countCacheSize() {
        double cachesize = 0;
        File[] fileList;

        int i;
        fileList = directory.listFiles();
        for (File f : fileList) {
            if (f.getName().endsWith(".data") == true) {
                cachesize += f.length();
            }
        }
        //Have the result in MegaByte
        cachesize = cachesize / (1024 * 1024);
        //create a new format to show only 3 digits
        DecimalFormat f = new DecimalFormat();
        f.setMaximumFractionDigits(3);
        // System.out.println(i);
        System.out.println("taille du cacheé" + cachesize);
        return f.format(cachesize);
    }

    /**
     * Get the main informations about all the rules
     *
     * @return StringBuilder to complete the html page
     */
    public StringBuilder showRulesInformations() {
        StringBuilder rule = new StringBuilder();
        for (Rule tmp : rules) {
            rule.append("<TR><TD>");
            rule.append(tmp.getNameRule());
            rule.append("<TD>");
            rule.append(String.valueOf(tmp.getMaximalSpeed()));
            rule.append("<TD>");
            rule.append(String.valueOf(tmp.getMinimalSpeed()));
            rule.append("<TD>");
            rule.append(String.valueOf(tmp.getWeight()));
            rule.append("</TR>");
        }
        return rule;
    }

    /**
     * Create a thread to display the html configuration page
     */
    @Override
    public void run() {
        while (true) {
            SocketChannel channel;
            synchronized (serverSocket) {
                try {
                    channel = serverSocket.accept();
                } catch (IOException ex) {
                    logger.severe("Error on the accept. Shutting down the thread. " + ex);
                    return;
                }
            }
            try {
                // Accepting a client.

                // Handling the client.
                //BufferedReader socketReader = null;
                //SocketChannel channel = socket.getChannel();
                ByteBuffer buffer = ByteBuffer.allocate(8092);
                channel.read(buffer);
                buffer.position(0);
                int dataStart = HeaderHttp.bufferHaveHttpHeader(buffer);
                buffer.position(0);
                HeaderHttp headerHttp = new HeaderHttp(buffer, dataStart);
                buffer.position(dataStart);

                CharBuffer cb = Charset.forName("ISO-8859-1").newDecoder().decode(buffer);
                Scanner sc = new Scanner(cb);

                //socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                //BufferedWriter socketWriter = new BufferedWriter(new OutputStreamWriter());
                //String line = socketReader.readLine();

                //while (!Thread.interrupted()) {
                //String[] cmd = line.split(" ");

                if (headerHttp.getHttpMethod().equals(HttpMethods.GET)) {
                    CharsetEncoder newEncoder = Charset.forName("ISO-8859-1").newEncoder();
                    channel.write(newEncoder.encode(CharBuffer.wrap(pageHtml())));
                    continue;
                }

                if (headerHttp.getHttpMethod().equals(HttpMethods.POST)) {
                    String line = headerHttp.getUrlToCall();

                    //String line = sc.nextLine();
                    if (line.contains("Refresh")) {
                        CharsetEncoder newEncoder = Charset.forName("ISO-8859-1").newEncoder();
                        channel.write(newEncoder.encode(CharBuffer.wrap(pageHtml())));
                        continue;
                    }
                    if (line.contains("Clear")) {
                        File[] fileList = directory.listFiles();
                        for (int i = 0; i < fileList.length; i++) {
                            fileList[i].delete();
                        }
                        CharsetEncoder newEncoder = Charset.forName("ISO-8859-1").newEncoder();
                        channel.write(newEncoder.encode(CharBuffer.wrap(pageHtmlS())));
                        continue;
                    } else {

                        CharsetEncoder newEncoder = Charset.forName("ISO-8859-1").newEncoder();
                        channel.write(newEncoder.encode(CharBuffer.wrap("Error 400 !\n")));
                    }
                }
            } catch (HttpException ex) {
                Logger.getLogger(WebServer.class.getName()).log(Level.SEVERE, null, ex);
            } catch (CharacterCodingException ex) {
                Logger.getLogger(WebServer.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(WebServer.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    channel.close();
                } catch (IOException ex) {
                    Logger.getLogger(WebServer.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
}
